package com.lan;

import com.lan.antlr.ScriptParser;
import com.lan.model.CompilationLog;
import com.lan.model.Symbol;
import com.lan.model.Type;
import com.lan.model.symbol.*;
import com.lan.parse.SymbolTree;
import org.antlr.v4.runtime.ParserRuleContext;

import java.util.LinkedList;
import java.util.List;


public class ScriptContext {

    private SymbolTree symbolTree;

    private ScriptParser.ProgContext ast;

    //语义分析过程中生成的信息，包括普通信息、警告和错误
    private List<CompilationLog> logs = new LinkedList<CompilationLog>();


    public ScriptParser.ProgContext getAst() {
        return ast;
    }

    public void setAst(ScriptParser.ProgContext ast) {
        this.ast = ast;
    }

    private void scopeToString(StringBuffer sb, Scope scope, String indent) {
        sb.append(indent).append(scope).append('\n');
        for (Symbol symbol : scope.getSymbols()) {
            if (symbol instanceof Scope) {
                scopeToString(sb, (Scope) symbol, indent + "\t");
            } else {
                sb.append(indent).append("\t").append(symbol).append('\n');
            }
        }
    }

    /**
     * 通过名称查找Class。逐级Scope查找。
     *
     * @param scope
     * @param idName
     * @return
     */
    public Clazz lookupClass(Scope scope, String idName) {
        Clazz rtn = scope.getClass(idName);
        if (rtn == null && scope.getScope() != null) {
            rtn = lookupClass(scope.getScope(), idName);
        }
        return rtn;
    }
//
//    public Type lookupType(String idName) {   //TODO 单纯根据名称并不严密
//        Type rtn = null;
//        for (Type type : types) {
//            if (type.getName().equals(idName)) {
//                rtn = type;
//                break;
//            }
//        }
//        return rtn;
//    }

    /**
     * 通过方法的名称和方法签名查找Function。逐级Scope查找。
     *
     * @param scope
     * @param idName
     * @param paramTypes
     * @return
     */
    public Function lookupFunction(Scope scope, String idName, List<Type> paramTypes) {
        Function rtn = scope.getFunction(idName, paramTypes);
        if (rtn == null && scope.getScope() != null) {
            rtn = lookupFunction(scope.getScope(), idName, paramTypes);
        }
        return rtn;
    }

    /**
     * 查找函数型变量，逐级查找。
     *
     * @param scope
     * @param idName
     * @param paramTypes
     * @return
     */
    public Variable lookupFunctionVariable(Scope scope, String idName, List<Type> paramTypes) {
        Variable rtn = scope.getFunctionVariable(idName, paramTypes);
        if (rtn == null && scope.getScope() != null) {
            rtn = lookupFunctionVariable(scope.getScope(), idName, paramTypes);
        }
        return rtn;
    }

    /**
     * 通过名称查找Variable。逐级Scope查找。
     *
     * @param scope
     * @param idName
     * @return
     */
    public Variable lookupVariable(Scope scope, String idName) {
        Variable rtn = scope.getVariable(idName);
        if (rtn == null && scope.getScope() != null) {
            rtn = lookupVariable(scope.getScope(), idName);
        }
        return rtn;
    }


    /**
     * 逐级查找函数（或方法）。仅通过名字查找。如果有重名的，返回第一个就算了。//TODO 未来应该报警。
     *
     * @param scope
     * @param name
     * @return
     */
    public Function lookupFunction(Scope scope, String name) {
        Function rtn = null;
        if (scope instanceof Clazz) {
            rtn = getMethodOnlyByName((Clazz) scope, name);
        } else {
            rtn = getFunctionOnlyByName(scope, name);
        }
        if (rtn == null && scope.getScope() != null) {
            rtn = lookupFunction(scope.getScope(), name);
        }

        return rtn;
    }

    //对于类，需要连父类也查找
    private Function getMethodOnlyByName(Clazz theClazz, String name) {
        Function rtn = getFunctionOnlyByName(theClazz, name);
        return rtn;
    }

    private Function getFunctionOnlyByName(Scope scope, String name) {
        for (Symbol s : scope.getSymbols()) {
            if (s instanceof Function && s.getName().equals(name)) {
                return (Function) s;
            }
        }
        return null;
    }


    /**
     * 记录编译错误和警告
     *
     * @param message
     * @param type    信息类型，ComplilationLog中的INFO、WARNING和ERROR
     * @param ctx
     */
    public void log(String message, int type, ParserRuleContext ctx) {
        CompilationLog log = new CompilationLog();
        log.setCtx(ctx);
        log.setMessage(message);
        log.setLine(ctx.getStart().getLine());
        log.setPositionInLine(ctx.getStart().getStartIndex());
        log.setType(type);
        logs.add(log);
        System.out.println(log);
    }

    public void log(String message, ParserRuleContext ctx) {
        log(message, CompilationLog.ERROR, ctx);
    }

    public void print() {

    }

    public SymbolTree getSymbolTree() {
        return symbolTree;
    }

    public void setSymbolTree(SymbolTree symbolTree) {
        this.symbolTree = symbolTree;
    }
}
